/*--------------------------------------------------------------------------------------*\
**
** adv_blacksmith.cpp
**
** Heroes IV
** Copyright 2000, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "adv_blacksmith.h"

#include <algorithm>

#include "adv_object_type.h"
#include "adventure_frame.h"
#include "adventure_map.h"
#include "adventure_sounds.h"
#include "ai_value.h"
#include "army.h"
#include "artifact_properties.h"
#include "artifact_slot.h"
#include "button_cache.h"
#include "default_artifacts.h"
#include "default_artifact_properties.h"
#include "dialog_blacksmith.h"
#include "elements_of.h"
#include "enum_operations.h"
#include "hero_keyword_replacer.h"
#include "mouse_event.h"
#include "music.h"
#include "object_registration.h"
#include "player.h"
#include "random.h"
#include "simple_dialog.h"

extern  t_bitmap_group_cache    k_blacksmith_background_bitmaps;
extern  t_bitmap_group_cache    k_blacksmith_picture_bitmaps[];
extern  t_button_cache          k_l_arrow;
extern  t_button_cache          k_r_arrow;
extern  t_bitmap_group_cache    k_center_box;

static t_object_registration<t_adv_blacksmith> k_registration( k_adv_object_blacksmith );

/*
** Items for generic blacksmith (adventure object).  Randomly pick
** from this list.
*/
static t_artifact_type items_table [] =
{
	k_artifact_axe,
    k_artifact_chainmail,
	k_artifact_crossbow,
	k_artifact_leather_armor,
    k_artifact_plate_mail, // plate armor
    k_artifact_shield,
    k_artifact_telescope
};

static t_artifact_type long_items_table [] =
{
	k_artifact_greatsword,
	k_artifact_longbow,
    k_artifact_longsword,
    k_artifact_mages_staff
};

typedef std::map< float, int > t_purchase_options;

/*
** Return a vector of all potions
*/
static std::vector< t_artifact_type > get_potion_vector()
{
	std::vector< t_artifact_type > result;

	result.reserve(22); // Current count, won't break anything if it changes

	for ( t_artifact_type type = t_artifact_type(0); type < k_artifact_type_count; enum_incr( type ) ) 
	{
		if ( !is_cut( type ) && get_slot( type ) == k_artifact_slot_potion )
		{
			result.push_back( type );
		}
	}

	return result;
}

/*
** Blacksmith object constructor - not a single use object, but just use this class.
*/
t_adv_blacksmith::t_adv_blacksmith(  std::string const& source )
         : t_single_use_object( source )
{
	std::fill( &m_available_potions[0], &m_available_potions[ ELEMENTS_OF( m_available_potions ) ], k_artifact_none);
	std::fill( &m_available_items[0], &m_available_items[ ELEMENTS_OF( m_available_items ) ], k_artifact_none);
	std::fill( &m_available_long_items[0], &m_available_long_items[ ELEMENTS_OF( m_available_long_items ) ], k_artifact_none);
}

/*
** Player visits this blacksmith.
*/
void t_adv_blacksmith::activate_trigger( t_army* army_ptr, t_adv_map_point const& point, 
		                               t_direction direction, t_adventure_frame* frame_ptr )
{

	t_counted_ptr<t_dialog_blacksmith> dialog_ptr;

    // Set player visited.
	m_visited[army_ptr->get_owner_number()] = true;

    /*
    ** Create and show dialog, and let user buy from this blacksmith.
    */
	dialog_ptr = new t_dialog_blacksmith( frame_ptr );
	dialog_ptr->init_dialog( frame_ptr, army_ptr, m_available_potions, m_available_items, m_available_long_items);
	t_sound_cache music = get_music_playing();
	stop_music();
	get_dialog_sound( k_dialog_sound_marketplace )->play( get_sound_volume() );
	dialog_ptr->run_modal();
	play_music( music );
    
	frame_ptr->update_funds();
}

/*
** Randomly choose items and potions for sale at generic blacksmith.
*/
void t_adv_blacksmith::create_items_list()
{
	static std::vector< t_artifact_type > const available_potions( get_potion_vector() );
	static std::vector< t_artifact_type > const available_items( &items_table[0], &items_table[ ELEMENTS_OF( items_table ) ] );
	static std::vector< t_artifact_type > const available_long_items( &long_items_table[0], &long_items_table[ ELEMENTS_OF( long_items_table ) ] );

	if ( m_available_potions[0] != k_artifact_none )
	{
		assert( false );
		return;
	}

 	std::vector< bool >				used;
    int                             i;
    int                             item_index = 0;
	t_artifact_set const &			allowed_artifacts = m_map->get_allowed_artifacts();
	int								num_allowed;

    /*----------------------------------------------------------------------------------------------*\
    ** Build list of available potions.
    \*----------------------------------------------------------------------------------------------*/
	used.resize( available_potions.size(), false );

	// Count number of potions on the allowed list
	num_allowed = 0;

	for ( i = 0; i < (int)available_potions.size(); i++ )
	{
		if ( allowed_artifacts[ available_potions[i] ] )
			num_allowed++;
	}

    for (i=0; i<k_max_potions; i++)
    {
        /*
        ** Get random index of potion to add.
        */
		do
		{
			item_index = (random( 0, (available_potions.size() -1 )));
		}
		while ( used[ item_index ] || ( !allowed_artifacts[ available_potions[item_index] ] && num_allowed > 0 ) );

        m_available_potions[i] = available_potions[item_index];

        // Remove from list so it won't be picked again.
        used[ item_index ] = true;
		num_allowed--;
    }
    
    /*----------------------------------------------------------------------------------------------*\
    ** Build list of available regular-sized items.
    \*----------------------------------------------------------------------------------------------*/
    /*
    ** There is (k_max_items-1) number of regular-sized
    ** items (as opposed to long items).
    */
 	used.assign( available_items.size(), false );

	// Count number of items on the allowed list
	num_allowed = 0;

	for ( i = 0; i < (int)available_items.size(); i++ )
	{
		if ( allowed_artifacts[ available_items[i] ] )
			num_allowed++;
	}

    for (i=0; i<(k_max_items-1); i++)
    {
        /*
        ** Get random index of potion to add.
        */
		do 
		{
			item_index = (random( 0, (available_items.size()-1) ));
		} 
		while ( used[ item_index ] || ( !allowed_artifacts[ available_items[item_index] ] && num_allowed > 0 ) );

        m_available_items[i] = available_items[item_index];

        // Remove from list so it won't be picked again.
        used[ item_index ] = true;
		num_allowed--;
    }

    /*
    ** There is 1 long-sized item.
    */

	// Count number of long items on the allowed list
	num_allowed = 0;

	for ( i = 0; i < (int)available_long_items.size(); i++ )
	{
		if ( allowed_artifacts[ available_long_items[i] ] )
			num_allowed++;
	}

	do
	{
		item_index = (random( 0, (available_long_items.size() - 1) ));
	}
	while ( !allowed_artifacts[ available_items[item_index] ] && num_allowed > 0 );

    m_available_long_items[0] = available_long_items[item_index];
}

int t_adv_blacksmith::get_version() const
{
	return 1;
}

/*
** Read saved game data.
*/
bool t_adv_blacksmith::read( std::streambuf&						stream, 
							 t_qualified_adv_object_type const&	type,
							 int									version )

{
    int i;

	if (version < 1)
	{
		return true;
	}

    t_single_use_object::read( stream, type, version );

    for (i=0; i<k_max_potions; i++)
    {
	    m_available_potions[i] = t_artifact_type( get<t_uint32>( stream ));
    }
    for (i=0; i<(k_max_items-1); i++)
    {
	    m_available_items[i] = t_artifact_type( get<t_uint32>( stream ));
    }
    m_available_long_items[0] = t_artifact_type( get<t_uint32>( stream ));

	return m_visited.read( stream );
}

void t_adv_blacksmith::place( t_adventure_map &		map,
						        t_adv_map_point const&	point )
{
	t_single_use_object::place( map, point );

	if ( m_available_potions[0] == k_artifact_none )
	{
		create_items_list();
	}
}

/*
** Write save game data.
*/
bool t_adv_blacksmith::write( std::streambuf& stream ) const
{
    int i;
    
    t_single_use_object::write(stream);

    for (i=0; i<k_max_potions; i++)
    {
	    put<t_uint32>( stream, m_available_potions[i] );
    }
    for (i=0; i<(k_max_items-1); i++)
    {
	    put<t_uint32>( stream, m_available_items[i] );
    }
    put<t_uint32>( stream, m_available_long_items[0] );

	return m_visited.write( stream );
}
        
/*
** Show help - show what artifacts this blacksmith sells.
*/
void t_adv_blacksmith::right_click( t_mouse_event const& event,
		                               t_adventure_frame* adventure_frame )
{
	std::string				help_text;
	t_hero_keyword_replacer text_replacer;
    t_artifact				cur_artifact;
    int						i;
	int						player = get_map()->get_player_number();
	t_skill_mastery			information = get_information_level();

	if (information >= k_mastery_basic)
		m_visited[player] = true;

    // Visited?
	if (!m_visited[player])
	{
		help_text = get_text( "name" );
	    show_popup_text( help_text, event.screen_point );
        return;
	}

    // Potions.
    for (i=0; i<k_max_potions; i++)
    {
        // Create artifact on the fly...
        cur_artifact = get_default_artifact( m_available_potions[i] );

        // Add to text replacer object.
   	    text_replacer.add_artifact ( cur_artifact );
    }
    // Items.
    for (i=0; i<k_max_items; i++)
    {
        // Create artifact on the fly...
        cur_artifact = get_default_artifact( m_available_items[i] );

        // Add to text replacer object.
   	    text_replacer.add_artifact ( cur_artifact );
    }
    
	help_text = text_replacer( get_text("Help") );
	show_popup_text( help_text, event.screen_point );
}

void t_adv_blacksmith::visit( t_hero* hero )
{
    
}

void t_adv_blacksmith::calculate_purchase_options( t_purchase_options& purchase_options, t_creature_array const& army ) const
{
	for (int i = 0; i < t_creature_array::k_size; i++)
	{
		t_hero const* hero = army[i].get_const_hero();
		if (hero == NULL) 
			continue;

		for (int j=0; j < k_max_potions; j++)
		{
			t_artifact_value_query query_params( &army, hero, m_available_potions[j] );
			int cost = get_cost( m_available_potions[j] );
			float value = ai_value_of_artifact( query_params );
			
			if (value > 0)
				purchase_options.insert(t_purchase_options::value_type( value, cost ));
		}

		for (int j=0; j<k_max_items; j++)
		{
			t_artifact_value_query query_params( &army, hero, m_available_items[j] );
			int cost = get_cost( m_available_items[j] );
			float value = ai_value_of_artifact( query_params );
			
			if (value > 0)
				purchase_options.insert(t_purchase_options::value_type( value, cost ));
		}
	}
}

float t_adv_blacksmith::ai_value( t_adventure_ai const& ai, t_creature_array const& army, int move_cost ) const
{
	return 0.0f;
}


